home *** CD-ROM | disk | FTP | other *** search
- /* Define GTEST to cause a test main program at the end of this
- file to be compiled. Remove it to call glob_filename from a
- program with some other main.
- */
-
- /* Note: This code has been modfied to run on the
- Macintosh under THINK C 5.0. It is NOT the source as distributed
- by the Free Software Foundation as part of bash. Not even close.
- */
-
- /* File-name wildcard pattern matching for GNU.
- Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* To whomever it may concern: I have never seen the code which most
- Unix programs use to perform this function. I wrote this from scratch
- based on specifications for the pattern matching. --RMS. */
-
-
- #define D_NAMLEN(d) ((d)->d_namlen)
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "common.h"
- #include "dirent.h"
-
- #define bcopy(s,t,n) memmove(t,s,n)
- #define bcmp(b1,b2,n) memcmp(b1,b2,n)
- #define bzero(b,n) memset(b,0,n)
- extern void *alloca();
-
- #ifndef NULL
- #define NULL 0
- #endif
-
- /* Global variable which controls whether or not * matches .*.
- Non-zero means don't match .*. */
- int noglob_dot_filenames = 1;
-
- /* Return nonzero if PATTERN has any special globbing chars in it. */
- static int
- glob_pattern_p (pattern)
- char *pattern;
- {
- register char *p = pattern;
- register char c;
- int open = 0;
-
- while ((c = *p++) != '\0')
- switch (c)
- {
- case '?':
- case '*':
- return 1;
-
- case '[': /* Only accept an open brace if there is a close */
- open++; /* brace to match it. Bracket expressions must be */
- continue; /* complete, according to Posix.2 */
- case ']':
- if (open)
- return 1;
- continue;
-
- case '\\':
- if (*p++ == '\0')
- return 0;
- }
-
- return 0;
- }
-
- static int glob_match_after_star ();
-
- /* Match the pattern PATTERN against the string TEXT;
- return 1 if it matches, 0 otherwise.
-
- A match means the entire string TEXT is used up in matching.
-
- In the pattern string, `*' matches any sequence of characters,
- `?' matches any character, [SET] matches any character in the specified set,
- [!SET] matches any character not in the specified set.
-
- A set is composed of characters or ranges; a range looks like
- character hyphen character (as in 0-9 or A-Z).
- [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
- Any other character in the pattern must be matched exactly.
-
- To suppress the special syntactic significance of any of `[]*?!-\',
- and match the character exactly, precede it with a `\'.
-
- If DOT_SPECIAL is nonzero,
- `*' and `?' do not match `.' at the beginning of TEXT. */
-
- static int
- glob_match (pattern, text, dot_special)
- char *pattern, *text;
- int dot_special;
- {
- register char *p = pattern, *t = text;
- register char c;
-
- while ((c = *p++) != '\0')
- switch (c)
- {
- case '?':
- if (*t == '\0' || (dot_special && t == text && *t == '.'))
- return 0;
- else
- ++t;
- break;
-
- case '\\':
- if (*p++ != *t++)
- return 0;
- break;
-
- case '*':
- if (dot_special && t == text && *t == '.')
- return 0;
- return glob_match_after_star (p, t);
-
- case '[':
- {
- register char c1 = *t++;
- int invert;
-
- if (!c1)
- return (0);
-
- invert = ((*p == '!') || (*p == '^'));
- if (invert)
- p++;
-
- c = *p++;
- while (1)
- {
- register char cstart = c, cend = c;
-
- if (c == '\\')
- {
- cstart = *p++;
- cend = cstart;
- }
-
- if (c == '\0')
- return 0;
-
- c = *p++;
- if (c == '-')
- {
- cend = *p++;
- if (cend == '\\')
- cend = *p++;
- if (cend == '\0')
- return 0;
- c = *p++;
- }
- if (c1 >= cstart && c1 <= cend)
- goto match;
- if (c == ']')
- break;
- }
- if (!invert)
- return 0;
- break;
-
- match:
- /* Skip the rest of the [...] construct that already matched. */
- while (c != ']')
- {
- if (c == '\0')
- return 0;
- c = *p++;
- if (c == '\0')
- return 0;
- else if (c == '\\')
- ++p;
- }
- if (invert)
- return 0;
- break;
- }
-
- default:
- if (c != *t++)
- return 0;
- }
-
- return *t == '\0';
- }
-
- /* Like glob_match, but match PATTERN against any final segment of TEXT. */
-
- static int
- glob_match_after_star (pattern, text)
- char *pattern, *text;
- {
- register char *p = pattern, *t = text;
- register char c, c1;
-
- while ((c = *p++) == '?' || c == '*')
- if (c == '?' && *t++ == '\0')
- return 0;
-
- if (c == '\0')
- return 1;
-
- if (c == '\\')
- c1 = *p;
- else
- c1 = c;
-
- while (1)
- {
- if ((c == '[' || *t == c1) && glob_match (p - 1, t, 0))
- return 1;
- if (*t++ == '\0')
- return 0;
- }
- }
-
- /* Return a vector of names of files in the current directory.
- The names are not in any particular order.
- Wildcards at the beginning of PAT do not match an initial period.
-
- The vector is terminated by an element that is a null pointer.
-
- To free the space allocated, first free the vector's elements,
- then free the vector.
-
- Return 0 if cannot get enough memory to hold the pointer
- and the names.
-
- Return -1 if cannot access directory DIR.
- Look in errno for more information. */
-
- char **
- glob_filename (pat)
- char *pat;
- {
- struct globval
- {
- struct globval *next;
- char *name;
- };
-
- DIR *d;
- char *dir = ".";
- register struct dirent *dp;
- struct globval *lastlink;
- register struct globval *nextlink;
- register char *nextname;
- unsigned int count;
- int lose;
- register char **name_vector;
- register unsigned int i;
-
- d = opendir (dir);
- if (d == NULL)
- return (char **) -1;
-
- lastlink = 0;
- count = 0;
- lose = 0;
-
- /* Scan the directory, finding all names that match.
- For each name that matches, allocate a struct globval
- on the stack and store the name in it.
- Chain those structs together; lastlink is the front of the chain. */
- while (1)
- {
- dp = readdir (d);
- if (dp == NULL)
- break;
- if (dp->d_ino != 0
- && glob_match (pat, dp->d_name, noglob_dot_filenames))
- {
- nextlink = (struct globval *) alloca ((long) sizeof (struct globval));
- nextlink->next = lastlink;
- nextname = (char *) malloc ((size_t)(D_NAMLEN(dp) + 1));
- if (nextname == NULL)
- {
- lose = 1;
- break;
- }
- lastlink = nextlink;
- nextlink->name = nextname;
- bcopy (dp->d_name, nextname, (size_t) (D_NAMLEN(dp) + 1));
- ++count;
- }
- }
- (void) closedir (d);
-
- if (!lose)
- {
- name_vector = (char **) malloc ((size_t)((count + 1)
- * sizeof (char *)));
- lose |= name_vector == NULL;
- }
-
- /* Have we run out of memory? */
- if (lose)
- {
- /* Here free the strings we have got. */
- while (lastlink)
- {
- free (lastlink->name);
- lastlink = lastlink->next;
- }
- return NULL;
- }
-
- /* Copy the name pointers from the linked list into the vector. */
- for (i = 0; i < count; ++i)
- {
- name_vector[i] = lastlink->name;
- lastlink = lastlink->next;
- }
-
- name_vector[count] = NULL;
- return name_vector;
- }
-
-
- static int compar(const void *s1, const void *s2)
-
- {
- return strcmp(*(char **) s1, *(char **)s2);
- }
-
-
- struct lnode;
-
- struct lnode {
- char **argv_block;
- struct lnode *next;
- };
-
- /* Accept the address of argc and argv and return a new vector and
- count after filename globbing. This implementation does NOT
- recognize pathnames. Thinks like "/" and ":" will be treated
- as part of the filename. Effectively, you glob only within the
- current directory. The files found are sorted.
- */
-
- void glob_argv(argc, argv)
- int *argc;
- char ***argv;
- {
- int i, j;
- char **retval, **value;
- int TotalFiles = 0, NumFiles;
- struct lnode *tmp, *head=NULL, *cur;
-
- if (*argc < 2) return; /* Nothing to glob */
-
- for (i = 1; i < *argc; i++) {
- if (glob_pattern_p ((*argv)[i]))
- value = glob_filename ((*argv)[i]);
- else { /* Do nothing to names with no magic chars */
- value = (char **) malloc((size_t) 2*sizeof(char *));
- value[0] = (*argv)[i];
- value[1] = NULL;
- }
-
- if (value == NULL) {
- emitdata("%s\n", "Out of memory.");
- exit(1);
- } else if ((int) value == -1)
- emitdata("%s\n", *argv[i]);
- else {
- tmp = (struct lnode *) malloc((size_t) sizeof(struct lnode));
- tmp->next = NULL;
- tmp->argv_block = value;
- NumFiles = 0;
- for (j = 0; value[j] != NULL; j++) {
- TotalFiles++;
- NumFiles++;
- }
-
- qsort((void *) value, (size_t) NumFiles, sizeof(char *),
- compar);
- /* append to list */
- if (head == NULL) head =tmp;
- else {
- cur = head;
- while (cur->next != NULL) cur = cur->next;
- cur->next = tmp;
- }
- }
- } /* for */
-
- retval = (char **) malloc((size_t) (TotalFiles+1)*sizeof(char *));
- cur = head;
- retval[0] = (*argv)[0];
- i = 1;
- while (cur != NULL) {
- j = 0;
- while (cur->argv_block[j] != NULL) {
- retval[i] = cur->argv_block[j];
- i++;
- j++;
- }
- tmp = cur;
- cur = cur->next;
- free(tmp->argv_block);
- free(tmp);
- }
-
- *argc = TotalFiles+1;
- *argv = retval;
-
- }
-
- static short fini;
- static short curpos;
-
- static char *findfile(flist)
- char *flist;
- {
- int endpos;
- char *p;
-
- if (fini) return NULL;
-
- while (flist[curpos] == ' ' || flist[curpos] == '\t')
- curpos++; /* skip whitespace */
-
- endpos = curpos;
- while (flist[endpos] != ' ' && flist[endpos] != '\t' &&
- flist[endpos] != '\0') endpos++; /* skip to white space */
-
- if (endpos == curpos) return NULL;
- if (flist[endpos] == '\0') fini = 1;
-
- p = (char *) malloc((size_t) (endpos - curpos + 1));
- memcpy(p, &(flist[curpos]), (size_t) (endpos - curpos));
- p[endpos - curpos] = '\0';
-
- curpos = endpos + 1;
-
- return p;
- }
-
-
-
- void glob_filelist(flist, argc, argv)
- char *flist;
- int *argc;
- char ***argv;
- {
- int i, j;
- char **retval, **value;
- char *file;
- int TotalFiles = 0, NumFiles;
- struct lnode *tmp, *head=NULL, *cur;
-
- fini = 0;
- curpos = 0;
-
- while ((file = findfile(flist)) != NULL) {
-
- if (glob_pattern_p (file))
- value = glob_filename (file);
- else { /* Do nothing to names with no magic chars */
- value = (char **) malloc((size_t) 2*sizeof(char *));
- value[0] = file;
- value[1] = NULL;
- }
-
- if (value == NULL) {
- emitdata("%s\n", "Out of memory.");
- exit(1);
- } else if ((int) value == -1)
- emitdata("%s\n", *argv[i]);
- else {
- tmp = (struct lnode *) malloc((size_t) sizeof(struct lnode));
- tmp->next = NULL;
- tmp->argv_block = value;
- NumFiles = 0;
- for (j = 0; value[j] != NULL; j++) {
- TotalFiles++;
- NumFiles++;
- }
-
- qsort((void *) value, (size_t) NumFiles, sizeof(char *),
- compar);
- /* append to list */
- if (head == NULL) head =tmp;
- else {
- cur = head;
- while (cur->next != NULL) cur = cur->next;
- cur->next = tmp;
- }
- }
-
- } /* while */
-
- retval = (char **) malloc((size_t) (TotalFiles)*sizeof(char *));
- cur = head;
- i = 0;
- while (cur != NULL) {
- j = 0;
- while (cur->argv_block[j] != NULL) {
- retval[i] = cur->argv_block[j];
- i++;
- j++;
- }
- tmp = cur;
- cur = cur->next;
- free(tmp->argv_block);
- free(tmp);
- }
-
- *argc = TotalFiles;
- *argv = retval;
-
- }
-
- #ifdef GTEST
-
- #include <console.h>
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- unsigned int j;
-
- argc = ccommand(&argv);
- glob_argv(&argc, &argv);
-
- for (j = 0; j < argc; j++)
- printf ("%s\n", argv[j]);
- exit (0);
- }
-
- void *xmalloc(n)
- size_t n;
- {
- void *r = malloc(n);
-
- return r;
- }
-
- #endif /* TEST. */
-
-
-